package MonteCarlo;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import MonteCarloMultiThreaded.MonteCarloMultiThreaded;
import MonteCarloSingleThreaded.MonteCarloSingleThreaded;

public class MonteCarloGUI extends JFrame implements ActionListener {
	
	private static final long serialVersionUID = 1L;
	private static final String fileName = "MonteCarloArg.txt";
	
	private JComboBox<String> CallPutFlag;
	private JComboBox<String> SelectAlgo;
	private List<JLabel> labels;
	private List<JComboBox<String>> comboBoxes;
	private JButton calcMonteCarlo;
	private JLabel result;
	
	private boolean running;
	private int count;
	
	protected void frameInit() {
		super.frameInit();
		getContentPane().setLayout(new GridLayout(11, 2));
		// Option types definition
		String[] optionTypes = { "Call", "Put" };
		CallPutFlag = new JComboBox<String>(optionTypes);
		// Option about the two algorithms available definition
		String[] optionAlgo = { "Standard", "Thread Version" };
		SelectAlgo = new JComboBox<String>(optionAlgo);
		// Label definitions
		labels = new ArrayList<JLabel>();
		labels.add(new JLabel("Algorithm to run : "));
		labels.add(new JLabel("Type of Option"));
		labels.add(new JLabel("Current Price : "));
		labels.add(new JLabel("Strike Price : "));
		labels.add(new JLabel("Time to Maturity : "));
		labels.add(new JLabel("Discount Rate : "));
		labels.add(new JLabel("Cost to carry Rate : "));
		labels.add(new JLabel("Volatility : "));
		labels.add(new JLabel("Number of steps : "));
		labels.add(new JLabel("Number of Simulations : "));
		
		// Get the options for every MonteCarlo parameters from a file
		List<String[]> options = null;
		try {
			options = ReadFile.readFile(fileName);
		} catch (FileNotFoundException e) {
			JOptionPane.showMessageDialog(this,
				    "Configuration file not found : default values will be used.",
				    "Warning",
				    JOptionPane.WARNING_MESSAGE);
			options = null;
		} catch (IOException e) {
			JOptionPane.showMessageDialog(this,
				    "Error while reading configuration file : default values will be used.",
				    "Warning",
				    JOptionPane.WARNING_MESSAGE);
			options = null;
		}
		
		// Comboboxes definitions
		comboBoxes = new ArrayList<JComboBox<String>>();
		if(options != null)
		{
			for(int i=0;i<8;i++)
			{
				comboBoxes.add(new JComboBox<String>(options.get(i)));
			}
		}
		else
		{
			String[][] defaultValues = { {"40"}, {"50"}, {"0.5"}, {"0.06"}, {"0.1"}, {"0.45"}, {"168"}, {"100000"} };
			for(int i=0;i<8;i++)
			{
				comboBoxes.add(new JComboBox<String>(defaultValues[i]));
			}
		}
		// Add the element to the GUI
		getContentPane().add(labels.get(0));
		getContentPane().add(SelectAlgo);
		getContentPane().add(labels.get(1));
		getContentPane().add(CallPutFlag);
		for(int i=2;i<=9;i++)
		{
			getContentPane().add(labels.get(i));
			getContentPane().add(comboBoxes.get(i-2));
		}
		
		calcMonteCarlo = new JButton("Compute Monte Carlo");
		getContentPane().add(calcMonteCarlo);
		
		result = new JLabel();
		getContentPane().add(result);
		// Add action listener to react to the button
		calcMonteCarlo.addActionListener(this);
	}
	
	
	
	
	@Override
	public void actionPerformed(ActionEvent e) {
		// New thread to compute the MonteCarlo algorithm and keep the GUI reactive
		new Thread() {
			public void run() {
				String callPutFlag;
				// Disable the button to avoid several operations at the same time
				calcMonteCarlo.setEnabled(false);
				// Check the type of option chosen
				if(CallPutFlag.getSelectedItem().equals("Call"))
					callPutFlag = "c";
				else
					callPutFlag = "p";
				// Get every parameters
				double S = Double.parseDouble((String) comboBoxes.get(0).getSelectedItem());
				double X = Double.parseDouble((String) comboBoxes.get(1).getSelectedItem());
				double T = Double.parseDouble((String) comboBoxes.get(2).getSelectedItem()); 
				double r = Double.parseDouble((String) comboBoxes.get(3).getSelectedItem()); 
				double b = Double.parseDouble((String) comboBoxes.get(4).getSelectedItem()); 
				double v = Double.parseDouble((String) comboBoxes.get(5).getSelectedItem()); 
			
				int nSteps 		 = Integer.parseInt((String) comboBoxes.get(6).getSelectedItem()); 
				int nSimulations = Integer.parseInt((String) comboBoxes.get(7).getSelectedItem());
					
				Double res = null;
				double timeBefore;
				// Start counting
				new Thread() {
					public void run() {
						startCounting();
					}
				}.start();
				// Check the algorithm chosen
				if(SelectAlgo.getSelectedItem().equals("Standard"))
				{
					timeBefore = (double) System.currentTimeMillis();
						
					res = new Double(	
							MonteCarloSingleThreaded.MonteCarloStandardOption(callPutFlag, S, X, T, r, b, v, nSteps, nSimulations)
							);
				}
				else
				{
					timeBefore = (double) System.currentTimeMillis();
						
					try {
						res = new Double(
								MonteCarloMultiThreaded.MonteCarloThreadOption(callPutFlag, S, X, T, r, b, v, nSteps, nSimulations)
								);
					} catch (InterruptedException | ExecutionException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				// Stop counting
				running = false;
				// Display result and time to process
				result.setText( res.toString() + " in " 
							+ (((double)System.currentTimeMillis() - timeBefore) / 1000)
							+ "s");
					
				calcMonteCarlo.setEnabled(true);
					
				}
		}.start();
	}
	
	private void startCounting() {
		running = true;
		count = 0;
		while(running) {
		    result.setText(String.format("%d", count));
		 	try {
		 		Thread.sleep(1000);
		 	} catch (InterruptedException ex) {
		 		throw new RuntimeException(ex);
		 	}
		 	count++;
		}
	}

}
